﻿using System;
using System.Collections.Generic;
using System.IO;

namespace TK
{
    public partial class CustomSerializer
    {
        readonly CustomSerializerSettings settings;
        public static string[] AssemblyDirectories = new string[0];

        public CustomSerializer()
        {
            settings = new CustomSerializerSettings(true, true, CustomSerializerConvertError.DefaultValue);
        }

        public CustomSerializer(CustomSerializerSettings settings)
        {
            this.settings = settings;
        }

        public void Serialize(Stream stm, object o, int version = 0)
        {
            if (o == null) return;
            var state = new CustomSerializerState(stm, settings);
            writeValue(state, o, null);
            state.writeHeaders();
        }

        public object Deserialize<T>(Stream stm)
        {
            return (T) Deserialize(stm, typeof (T));
        }

        public object Deserialize(Stream stm, Type rootType)
        {
            var state = new CustomSerializerState(stm, settings);
            state.readHeaders();
            bool success = false;
            var obj = readValue(state, rootType, rootType, null, out success);
            return obj;
        }

#if DEBUG
        public override string ToString()
        {
            return "Compress: " + (settings.CompressNames ? "YES" : "NO ");
        }
#endif
        #region simple types
        static readonly Dictionary<Type, TypeHandler> SimpleTypes = new Dictionary<Type, TypeHandler>();       

        static CustomSerializer()
        {
            SimpleTypes.Add(typeof(bool), new THBool());
            
            SimpleTypes.Add(typeof(byte), new THByte());
            SimpleTypes.Add(typeof(sbyte), new THSignedByte());
            SimpleTypes.Add(typeof(Int16), new THInt16());
            SimpleTypes.Add(typeof(UInt16), new THUInt16());
            SimpleTypes.Add(typeof(Int32), new THInt32());
            SimpleTypes.Add(typeof(UInt32), new THUInt32());
            SimpleTypes.Add(typeof(UInt64), new THUInt64());
            SimpleTypes.Add(typeof(Int64), new THInt64());
            SimpleTypes.Add(typeof(Single), new THSingle());
            SimpleTypes.Add(typeof(Double), new THDouble());
            SimpleTypes.Add(typeof(decimal), new THDecimal());
            SimpleTypes.Add(typeof(Guid), new THGuid());
            
            SimpleTypes.Add(typeof(DateTime), new THDateTime());
            SimpleTypes.Add(typeof(DateTimeOffset), new THDateTimeOffset());
            SimpleTypes.Add(typeof(TimeSpan), new THTimeSpan());
            
            SimpleTypes.Add(typeof(char), new THChar());
            SimpleTypes.Add(typeof(string), new THString());
            SimpleTypes.Add(typeof(byte[]), new THByteArray());
        }
        #endregion
    }

    public enum CustomSerializerConvertError
    {
        Throw,
        DefaultValue,
        CallHandler
    }

    public class CustomSerializerSettings
    {
        public readonly CustomSerializerConvertError ConvertBehavior;
        public readonly bool IncludeProperties;
        public readonly bool IncludeFields;
        public CustomSerializerConverterDelegate CustomSerializerConverter;
        public bool CompressNames;
        public readonly Dictionary<string, Type> ClassMap = new Dictionary<string, Type>();

        public CustomSerializerSettings(bool includeProperties = true, bool includeFields = true, CustomSerializerConvertError convertBehavior = CustomSerializerConvertError.DefaultValue)
        {
            IncludeFields = includeFields;
            IncludeProperties = includeProperties;
            ConvertBehavior = convertBehavior;
        }
    }

    public delegate object CustomSerializerConverterDelegate(object value, Type ownerType, string propertyName, Type targetType);
}